package ar.edu.itba.it.cg.grupo01.impl.scene;

import java.util.HashSet;
import java.util.Set;

import javax.vecmath.Point3d;

import com.google.common.collect.ImmutableSet;

import ar.edu.itba.it.cg.grupo01.api.scene.Scene;
import ar.edu.itba.it.cg.grupo01.api.shape.Shape;
import ar.edu.itba.it.cg.grupo01.impl.IntersectionFactory;
import ar.edu.itba.it.cg.grupo01.impl.shape.Box;
import ar.edu.itba.it.cg.grupo01.impl.shape.CompositeShape;
import ar.edu.itba.it.cg.grupo01.impl.shape.Rectangle;
import ar.edu.itba.it.cg.grupo01.impl.shape.Sphere;
import ar.edu.itba.it.cg.grupo01.impl.shape.Triangle;

public enum InMemoryScene {

	SCENE_1 {
		@Override
		public Scene getScene(IntersectionFactory intersectionFactory) {
			Set<Shape> shapes = new HashSet<Shape>();
			
			double baseSide=5;
			double pyramidHeight=5;
			double topSphereRadius=1;
			double outerSphereRadius=0.5;
			double outerSphereDistance=3+outerSphereRadius;
			//rectangular base points
			Point3d p1=new Point3d(baseSide/2,0, baseSide/2);
			Point3d p2=new Point3d(baseSide/2,0,-baseSide/2);
			Point3d p3=new Point3d(-baseSide/2,0,baseSide/2);
			Point3d p4=new Point3d(-baseSide/2,0,-baseSide/2);
			Point3d top= new Point3d(0,pyramidHeight,0);
			
			Rectangle base= new Rectangle(p1,p2,p3,intersectionFactory);
			
			//triangles forming the pyramid
			Triangle t1= new Triangle(p1,top, p2, intersectionFactory);
			Triangle t2= new Triangle(p1,top, p3,  intersectionFactory);
			Triangle t3= new Triangle(p3,top, p4, intersectionFactory);
			Triangle t4= new Triangle(p2,top, p4,  intersectionFactory);
			
			//Let's build the pyramid
			CompositeShape pyramid = new CompositeShape(ImmutableSet.of(base,t1,t2,t3,t4), intersectionFactory);
			
			//sphere on top of the pyramid
			Sphere topSphere=new Sphere(new Point3d(0,pyramidHeight+topSphereRadius,0), topSphereRadius, intersectionFactory);
			
			//outer spheres
			Point3d s1=(Point3d) p1.clone();
			s1.add(new Point3d(outerSphereDistance,0,0));
			Sphere sp1=new Sphere(s1,outerSphereRadius,intersectionFactory);
			
			Point3d s2=(Point3d) p2.clone();
			s2.add(new Point3d(outerSphereDistance,0,0));
			Sphere sp2=new Sphere(s2,outerSphereRadius,intersectionFactory);
			
			Point3d s3=(Point3d) p3.clone();
			s3.add(new Point3d(-outerSphereDistance,0,0));
			Sphere sp3=new Sphere(s3,outerSphereRadius,intersectionFactory);
			
			Point3d s4=(Point3d) p4.clone();
			s4.add(new Point3d(-outerSphereDistance,0,0));
			Sphere sp4=new Sphere(s4,outerSphereRadius,intersectionFactory);
			


			shapes.add(pyramid);
			shapes.add(topSphere);
			shapes.add(sp1);
			shapes.add(sp2);
			shapes.add(sp3);
			shapes.add(sp4);
			
			return new SceneImpl(shapes);
			
		}

		@Override
		public String getSceneName() {
			return "scene1.sc";
		}
	},
	SCENE_2 {
		@Override
		public Scene getScene(IntersectionFactory intersectionFactory) {
			Set<Shape> shapes = new HashSet<Shape>();
			
			// 64 spheres of radius 1 in a 4 x 4 x 4 cube distribution with a
			// separation of 0.5
			int spheresPerFace = 4;
			double distance = 0.5;
			double radius = 0.5;
			double interval = spheresPerFace * radius
			+ (spheresPerFace / 2.0 - 1) * distance + distance / 2
			- radius;
			for (double x = -interval; x <= interval; x += 2 * radius
			+ distance) {
				for (double y = -interval; y <= interval; y += 2 * radius
				+ distance) {
					for (double z = -interval; z <= interval; z += 2 * radius
					+ distance) {
						shapes.add(new Sphere(new Point3d(x, y, z), radius,
								intersectionFactory));
					}
				}
			}
			
			return new SceneImpl(shapes);
		}

		@Override
		public String getSceneName() {
			return "scene2.sc";
		}
	},SCENE_3 {
		@Override
		public Scene getScene(IntersectionFactory intersectionFactory) {
			
			Set<Shape> shapes = new HashSet<Shape>();
			
			// 3 cubes of side 2.0 and 2 spheres of radius 1.0
			// intercalated centered on x-axis, resting on the plane y=0
			// separated by 0.5. centers of figures must be cut by plane z=0.
			
			double radius = 1.0;
			
			// cube in the center
			shapes.add(new Box(new Point3d(-1.0, 0, -1.0), new Point3d(1.0, 2.0, 1.0), intersectionFactory));
			
			// spheres on each side of the centered cube
			shapes.add(new Sphere(new Point3d(-2.0, 1, 0.0), radius, intersectionFactory));
			shapes.add(new Sphere(new Point3d(2.0, 1, 0.0), radius, intersectionFactory));
			
			
			// cubes on the outer side of each sphere
			//shapes.add(new Box(new Point3d(-4, 0, -1.0), new Point3d(1.0, 2.0, -1.0), intersectionFactory));
			shapes.add(new Box(new Point3d(3.0, 0, -1.0), new Point3d(5.0, 2.0, 1.0), intersectionFactory));
			shapes.add(new Box(new Point3d(-5.0, 0, -1.0), new Point3d(-3.0, 2.0, 1.0), intersectionFactory));
			shapes.add(new Box(new Point3d(3.0, 0, -1.0), new Point3d(5.0, 2.0, 1.0), intersectionFactory));
			
		
			return new SceneImpl(shapes);
		}
		

		@Override
		public String getSceneName() {
			return "scene3.sc";
		}
	},
	SCENE_4 {
		@Override
		public Scene getScene(IntersectionFactory intersectionFactory) {
			
			Set<Shape> shapes = new HashSet<Shape>();
			
			// 3 cubes of side 2.0 and 2 spheres of radius 1.0
			// intercalated centered on x-axis, resting on the plane z=0
			// separated by 0.5. the scene must be centered on the y-axis
			
			double radius = 0.5;
			
			// cube in the center
			shapes.add(new Sphere(new Point3d(0.0, 0.0, 0.0), radius, intersectionFactory));
			
			return new SceneImpl(shapes);
		}
		
		@Override
		public String getSceneName() {
			return "scene4.sc";
		}
	};

	public abstract Scene getScene(IntersectionFactory intersectionFactory);

	public abstract String getSceneName();

	public static InMemoryScene forName(final String name) {
		final String lowerSceneName = name.toLowerCase().trim();

		for (final InMemoryScene sceneName : InMemoryScene.values()) {
			if (lowerSceneName.equals(sceneName.getSceneName())) {
				return sceneName;
			}
		}

		throw new IllegalArgumentException("Invalid scene name " + name);
	}
}
